package org.example.Service.Impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.WebSocket;
import org.example.Domain.Player;
import org.example.Domain.PlayerRequest;
import org.example.Domain.RoleContent;
import org.example.Dto.AgentDTO;
import org.example.Entity.Agent;
import org.example.Listener.CharacterSimulationListener;
import org.example.Mapper.AgentMapper;
import org.example.Service.AiService;
import org.example.Vo.R;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import static org.example.Utils.AuthUtil.getSignature;

@Service
@Slf4j
public class AiServiceImpl implements AiService {

    @Autowired
    private AgentMapper agentMapper;

    private static final String appId = "24a3e0bb";
    private static final String apiSecret = "MjIwODhiOTQwODRlNDI4YTdhNDM1MDlm";

    private static final String playerId = "20f3775db4260e897dc22f194bc2ad65";

    // 用来缓存 用户的SseEmitter
    private static final Map<Object, SseEmitter> SSE_CACHE = new ConcurrentHashMap<>();

    @Override
    public R playerRegister(Player player) throws IOException {
        String url = "https://ai-character.xfyun.cn/api/open/player/register";
        System.out.println("url:" + url);
        PlayerRequest playerRequest = new PlayerRequest();
        BeanUtils.copyProperties(player, playerRequest);
        playerRequest.setAppId(appId);
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), JSON.toJSONString(playerRequest));
        long ts = System.currentTimeMillis();
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .addHeader("appId", appId)
                .addHeader("timestamp", String.valueOf(ts))
                .addHeader("signature", Objects.requireNonNull(getSignature(appId, apiSecret, ts)))
                .build();
        OkHttpClient client = new OkHttpClient();
        Response response = client.newCall(request).execute();
        R responseMsg = JSONObject.parseObject(response.body().string(), new TypeReference<R>() {
        });
        System.out.println(responseMsg);
        if (responseMsg.getCode() != 10000) {
            return R.error("玩家注册失败!");
        }
        return R.ok(responseMsg.getData());
    }

    @Override
    public R agentCreate(AgentDTO agentDTO) throws Exception {
        String url = "https://ai-character.xfyun.cn/api/open/agent/edit-character";
        System.out.println("url:" + url);
        agentDTO.setPlayerId(playerId);
        agentDTO.setAppId(appId);
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), JSONObject.toJSONString(agentDTO));
        long ts = System.currentTimeMillis();
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .addHeader("appId",appId)
                .addHeader("timestamp", String.valueOf(ts))
                .addHeader("signature", Objects.requireNonNull(getSignature(appId, apiSecret, ts)))
                .build();
        OkHttpClient client = new OkHttpClient();
        Response response = client.newCall(request).execute();
        R responseMsg = JSONObject.parseObject(response.body().string(), new TypeReference<R>() {
        });
        System.out.println(agentDTO);
        System.out.println(responseMsg);
        if (responseMsg.getCode() != 10000){
            throw new Exception("创建人格失败，responseMsg =" + responseMsg);
        }
        // 存入数据库
        Agent agent = Agent.builder()
                .agentId(responseMsg.getData().toString())
                .agentName(agentDTO.getAgentName())
                .hobby(agentDTO.getHobby())
                .agentType("示例人格")
                .description(agentDTO.getDescription())
                .identity(agentDTO.getIdentity())
                .keyPersonality(agentDTO.getKeyPersonality())
                .mission(agentDTO.getMission())
                .personalityDescription(agentDTO.getPersonalityDescription())
                .speaker(null)
                .build();
        agentMapper.insert(agent);
        return R.ok(responseMsg.getData());
    }

    @Override
    public SseEmitter getConn(Long key) {
        final SseEmitter sseEmitter = SSE_CACHE.get(key);
        if (sseEmitter != null) {
            return sseEmitter;
        } else {
            // 设置连接超时时间，需要配合配置项 spring.mvc.async.request-timeout: 600000 一起使用
            final SseEmitter emitter = new SseEmitter(600000L);
            // 注册超时回调，超时后触发
            emitter.onTimeout(() -> {
                log.info("连接已超时，正准备关闭，key = {}", key);
                SSE_CACHE.remove(key);
            });
            // 注册完成回调，调用 emitter.complete() 触发
            emitter.onCompletion(() -> {
                log.info("连接已关闭，正准备释放，key = {}", key);
                SSE_CACHE.remove(key);
                log.info("连接已释放，key = {}", key);
            });
            // 注册异常回调，调用 emitter.completeWithError() 触发
            emitter.onError(throwable -> {
                log.error("连接已异常，正准备关闭，key = {}", key, throwable);
                SSE_CACHE.remove(key);
            });
            System.out.println("放入Key=>" + key);
            SSE_CACHE.put(key, emitter);
            return emitter;
        }
    }

    @Override
    public CharacterSimulationListener characterSimulationChat(String question, StringBuilder answer,String agentId,String chatId,String preChatId) {
        String url = "wss://ai-character.xfyun.cn/api/open/interactivews/";
        // 构造url鉴权
        long ts = System.currentTimeMillis();
        String signature = getSignature(appId, apiSecret, ts);
        String requestUrl = url + chatId + "?" + "appId=" + appId + "&timestamp=" + ts + "&signature=" + signature;
        OkHttpClient client = new OkHttpClient.Builder().build();
        // 构建聊天请求
        JSONObject chatRequest = buildCharacterSimulationRequest(question, playerId, agentId,chatId, preChatId);
        System.out.println(chatRequest);
        // 构建websocket请求
        Request request = new Request.Builder().url(requestUrl).build();
        CharacterSimulationListener characterSimulationListener = new CharacterSimulationListener(answer);
        // 发起websocket请求
        WebSocket webSocket = client.newWebSocket(request, characterSimulationListener);
        if (chatRequest != null) {
            webSocket.send(chatRequest.toJSONString());
        }
        return characterSimulationListener;
    }

    private JSONObject buildCharacterSimulationRequest(String question, String playerId, String agentId,String chatId, String preChatId) {
        try {
            JSONObject requestJson = new JSONObject();

            JSONObject header = new JSONObject();
            header.put("app_id", appId);
            header.put("uid", playerId);
            header.put("agent_id", agentId);

            JSONObject parameter = new JSONObject();
            JSONObject chat = new JSONObject();
            chat.put("chat_id",chatId);
            chat.put("pre_chat_id",preChatId);

            JSONObject payload = new JSONObject();
            JSONObject message = new JSONObject();
            JSONArray text = new JSONArray();
            // 对于第一次开始对话 question为空 此时text应为空数组
            if ( question != null ) {
                RoleContent roleContent = new RoleContent();
                roleContent.setRole("user");
                roleContent.setContent(question);
                text.add(JSON.toJSON(roleContent));
            }
            message.put("text", text);
            payload.put("message", message);

            parameter.put("chat", chat);
            requestJson.put("header", header);
            requestJson.put("parameter", parameter);
            requestJson.put("payload", payload);

            return requestJson;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
